package com.agentframework.examples.jinhua;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author wangjun
 **/
public final class JinHuaComparator {

    private static final Map<String, Integer> rankMap = new HashMap<>();

    static {
        String[] ranks = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"};
        for (int i = 0; i < ranks.length; i++) {
            rankMap.put(ranks[i], i + 2); // 2 = 2, ..., A = 14
        }
    }

    enum HandType {

        BAO_ZI(6),     // 豹子
        SHUN_JIN(5),   // 顺金
        JIN_HUA(4),    // 金花
        SHUN_ZI(3),    // 顺子
        DUI_ZI(2),     // 对子
        DAN_ZHANG(1);  // 单张

        private final int rank;

        HandType(int rank) {
            this.rank = rank;
        }

        public int getRank() {
            return rank;
        }

    }

    static class Hand {
        List<String> cards;
        HandType type;
        List<Integer> sortedRanks;

        Hand(List<String> cards) {
            this.cards = cards;
            this.sortedRanks = cards.stream()
                    .map(JinHuaComparator::getCardRank)
                    .sorted(Comparator.reverseOrder())
                    .collect(Collectors.toList());
            this.type = evaluateType(cards);
        }
    }

    // 提取点数（如 J♠ → J）
    private static String getCardValue(String card) {
        return card.replaceAll("[♠♥♦♣]", "");
    }

    private static String getCardSuit(String card) {
        return card.replaceAll("[0-9JQKA]+", "");
    }

    private static int getCardRank(String card) {
        return rankMap.get(getCardValue(card));
    }

    public static HandType evaluateType(List<String> cards) {
        Set<String> suits = cards.stream().map(JinHuaComparator::getCardSuit).collect(Collectors.toSet());
        List<Integer> ranks = cards.stream().map(JinHuaComparator::getCardRank).sorted().toList();
        Set<Integer> distinctRanks = new HashSet<>(ranks);

        boolean isFlush = suits.size() == 1;
        boolean isStraight = isStraight(ranks);

        if (distinctRanks.size() == 1) return HandType.BAO_ZI;
        if (isFlush && isStraight) return HandType.SHUN_JIN;
        if (isFlush) return HandType.JIN_HUA;
        if (isStraight) return HandType.SHUN_ZI;
        if (distinctRanks.size() == 2) return HandType.DUI_ZI;

        return HandType.DAN_ZHANG;
    }

    private static boolean isStraight(List<Integer> sortedRanks) {
        // 普通顺子
        if (sortedRanks.get(2) - sortedRanks.get(1) == 1 && sortedRanks.get(1) - sortedRanks.get(0) == 1) {
            return true;
        }
        // 特殊顺子 A23
        return sortedRanks.contains(14) && sortedRanks.contains(2) && sortedRanks.contains(3);
    }

    public static int compareHands(List<String> hand1Cards, List<String> hand2Cards) {
        Hand h1 = new Hand(hand1Cards);
        Hand h2 = new Hand(hand2Cards);

        if (h1.type.getRank() != h2.type.getRank()) {
            return Integer.compare(h1.type.getRank(), h2.type.getRank());
        }

        // 相同牌型，按点数比较
        switch (h1.type) {
            case BAO_ZI -> {
                return Integer.compare(h1.sortedRanks.get(0), h2.sortedRanks.get(0));
            }
            case SHUN_JIN, SHUN_ZI -> {
                return compareStraight(h1.sortedRanks, h2.sortedRanks);
            }
            case DUI_ZI -> {
                int pair1 = findPairValue(h1.sortedRanks);
                int pair2 = findPairValue(h2.sortedRanks);
                if (pair1 != pair2) return Integer.compare(pair1, pair2);
                return Integer.compare(getKicker(h1.sortedRanks, pair1), getKicker(h2.sortedRanks, pair2));
            }
            default -> {
                for (int i = 0; i < 3; i++) {
                    if (!h1.sortedRanks.get(i).equals(h2.sortedRanks.get(i))) {
                        return Integer.compare(h1.sortedRanks.get(i), h2.sortedRanks.get(i));
                    }
                }
                return 0; // 平局
            }
        }
    }

    private static int compareStraight(List<Integer> r1, List<Integer> r2) {
        // 处理 A23 顺子
        int v1 = isA23(r1) ? 1 : r1.get(0);
        int v2 = isA23(r2) ? 1 : r2.get(0);
        return Integer.compare(v1, v2);
    }

    private static boolean isA23(List<Integer> ranks) {
        return ranks.contains(14) && ranks.contains(2) && ranks.contains(3);
    }

    private static int findPairValue(List<Integer> ranks) {
        if (Objects.equals(ranks.get(0), ranks.get(1))) return ranks.get(0);
        if (Objects.equals(ranks.get(1), ranks.get(2))) return ranks.get(1);
        return -1;
    }

    private static int getKicker(List<Integer> ranks, int pairValue) {
        for (int rank : ranks) {
            if (rank != pairValue) return rank;
        }
        return -1;
    }

}
